package cn.bbstone.pisces2.ui.parts;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Named;

import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.core.di.annotations.Optional;
import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.e4.ui.di.Focus;
import org.eclipse.e4.ui.di.UIEventTopic;
import org.eclipse.e4.ui.di.UISynchronize;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.services.IServiceConstants;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.bbstone.pisces2.cmm.Pi2ContextUtil;
import cn.bbstone.pisces2.cmm.UIConst;
import cn.bbstone.pisces2.listener.OpEnum;
import cn.bbstone.pisces2.model.FileListItem;
import cn.bbstone.pisces2.service.FileListService;
import cn.bbstone.pisces2.ui.base.enums.CmdEnum;
import cn.bbstone.pisces2.ui.base.notify.Pi2Events;
import cn.bbstone.pisces2.ui.job.JobService;
import cn.bbstone.pisces2.ui.views.FileListView;
import cn.bbstone.pisces2.util.FLIUtil;

public class FileListPart {
	private static Logger log = LoggerFactory.getLogger(FileListPart.class);

	@Inject
	private FileListService fileListService;

	@Inject
	IEventBroker eventBroker;

	@Inject
	UISynchronize sync;

	@Inject
	JobService jobService;

	FileListView viewer = null;

//	private TableViewer viewer;
////	private PersonFilter filter = new PersonFilter();
//	private FileListItemFilter filter = new FileListItemFilter();
//
//	// We use icons
//	private static Image CHECKED = null;// Activator.getImageDescriptor("icons/checked.gif").createImage();
//	private static Image UNCHECKED = null;// Activator.getImageDescriptor("icons/unchecked.gif").createImage();

	@Inject
	public FileListPart(@Named(IServiceConstants.ACTIVE_SHELL) Shell shell, MApplication app,
			IEclipseContext appContext) {
//		System.out.println(this.getClass().getSimpleName() + " constructed");
		log.info((this.getClass().getSimpleName() + " constructed"));

		viewer = new FileListView(shell);
//		CHECKED = new Image(shell.getDisplay(), getClass().getResourceAsStream(UIConst.ICON_CHECKED));
//		UNCHECKED = new Image(shell.getDisplay(), getClass().getResourceAsStream(UIConst.ICON_UNCHECKED));
	}

	@PostConstruct
	public void createControls(Composite parent) {
		log.info(this.getClass().getSimpleName() + " @PostConstruct method called.");

		viewer.renderUI(parent);

	}

	@Focus
	public void setFocus() {
//		viewer.getControl().setFocus();
		viewer.setFocus();
	}

	@PreDestroy
	public void dispose() {
//		if (CHECKED != null)
//			CHECKED.dispose();
//		if (UNCHECKED != null)
//			UNCHECKED.dispose();
	}

	@Inject
	@Optional
	void onClientBizMetaCreated(final @UIEventTopic(Pi2Events.CLIENT_BIZ_META_CREATED_FILELIST) CmdEnum cmdEnum) {
		// do load data
		viewer.setInput(new ArrayList<FileListItem>());
		viewer.refresh();
		eventBroker.post(Pi2Events.OPERATION, OpEnum.loading_file_list.getDisplayText());
		// startup job for load file list data
		Job job = Job.create("Update table", monitor -> {
//			monitor.beginTask("Load File List", 100);
			List<FileListItem> dataList = new ArrayList<>();
			int pageSize = 3000;
			long count = 0L;

			// load server file list(~/.fli_client/fli.idx)
			count = FLIUtil.getClientIndexCount();
			if (count > pageSize) { // load page
				long start = 0L;
				while (start < count) {
					List<FileListItem> pageData = fileListService.loadClientPage(start, pageSize);
					dataList.addAll(pageData);
					start += pageSize;
					if (start > count) {
						start = count;
					}
					String statusText = null;
					if (start == count) {
						statusText = MessageFormat.format(OpEnum.done_scan_file_list.getDisplayText(), start, count);
						;
					} else {
						statusText = MessageFormat.format(OpEnum.scaning_file_list.getDisplayText(), start, count);
					}
					eventBroker.post(Pi2Events.OPERATION, statusText);
				}
			} else { // load all
				long start = 0L;
				int size = (int)count;
				List<FileListItem> pageData = fileListService.loadClientPage(0L, size);
				dataList.addAll(pageData);
				String statusText = MessageFormat.format(OpEnum.done_scan_file_list.getDisplayText(), start, count);
				eventBroker.post(Pi2Events.OPERATION, statusText);
			}
//			monitor.worked(30);
			// If you want to update the UI
			sync.asyncExec(() -> {
				// do something in the user interface
				// e.g. set a text field
				viewer.setInput(dataList);
				viewer.refresh();
				eventBroker.post(Pi2Events.OPERATION, OpEnum.done_loading_file_list.getDisplayText());
			});
			return Status.OK_STATUS;
		});
		// if set rule, will used progress bar exclusive
		job.setRule(ResourcesPlugin.getWorkspace().getRoot());
//		job.setUser(true);
		// Start the Job
		job.schedule();

	}

	@Inject
	@Optional
	void onStartUpdateFileList(final @UIEventTopic(Pi2Events.SERVER_STARTUP_FILELIST) CmdEnum cmdEnum) {
		if (CmdEnum.startup.equals(cmdEnum)) {
			// only new/rerun need load/fresh file list
//			if (RunModeEnum.NEW.equals(Pi2ContextUtil.getRunMode()) || RunModeEnum.RERUN.equals(Pi2ContextUtil.getRunMode())) {
			// clear table viewer
			viewer.setInput(new ArrayList<FileListItem>());
			viewer.refresh();

			// TODO add new item to OpEnum, like:
			// OpEnum.s3_update_ui_after_startup.getDisplayText()
			eventBroker.post(Pi2Events.OPERATION, OpEnum.loading_file_list.getDisplayText());

			// startup job for load file list data
			Job job = Job.create("Update table", monitor -> {
//				monitor.beginTask("Load File List", 100);
//					SubMonitor subMonitor = SubMonitor.convert(monitor, 100);
				// convert to SubMonitor and set total number of work units
				// do something long running
//					List<FileListItem> dataList = fileListService.findAll(); //new ArrayList<FileListItem>(); // fileListService.findAll();

				List<FileListItem> dataList = new ArrayList<>();
//					fileListService.loadAll(dataList);
//				sync.asyncExec(() -> {
//					viewer.setInput(dataList);
//				});

				int pageSize = 3000;
				long count = 0L;
				// load server file list(~/.fli_server/fli.idx)
				if (UIConst.RUN_AS_SERVER.equals(Pi2ContextUtil.getRunAs())) {
					count = FLIUtil.getServerIndexCount();
					if (count > pageSize) {
						long start = 0L;
						while (start < count) {
							List<FileListItem> pageData = fileListService.loadPage(start, pageSize);
							dataList.addAll(pageData);
							start += pageSize;
							if (start > count) {
								start = count;
							}
							//
							String statusText = null;
							if (start == count) {
								statusText = MessageFormat.format(OpEnum.done_scan_file_list.getDisplayText(), start, count);
								;
							} else {
								statusText = MessageFormat.format(OpEnum.scaning_file_list.getDisplayText(), start, count);
							}
							eventBroker.post(Pi2Events.OPERATION, statusText);
//							sync.asyncExec(() -> {
//								viewer.setInput(dataList);
//								viewer.refresh();
////								// TODO scroll to end
//							});
						}
					} else { // load all
						long start = 0L;
						int size = (int)count;
						List<FileListItem> pageData = fileListService.loadPage(start, size);
						dataList.addAll(pageData);
						String statusText = MessageFormat.format(OpEnum.done_scan_file_list.getDisplayText(), start, count);
						eventBroker.post(Pi2Events.OPERATION, statusText);
					}
				}
//				monitor.worked(30);
//					subMonitor.split(30);

//					subMonitor.setWorkRemaining(70);

				// ...
				// If you want to update the UI
				sync.asyncExec(() -> {
					// do something in the user interface
					// e.g. set a text field
					viewer.setInput(dataList);
					viewer.refresh();
					eventBroker.post(Pi2Events.OPERATION, OpEnum.done_loading_file_list.getDisplayText());
				});
				return Status.OK_STATUS;
			});
			// if set rule, will used progress bar exclusive
			job.setRule(ResourcesPlugin.getWorkspace().getRoot());
//				job.setUser(true);
			// Start the Job
			job.schedule();
//			}
		}
	}
	
	@Inject
	@Optional
	void onServerShutdown(final @UIEventTopic(Pi2Events.SERVER_SHUTDOWN_FILELIST) String message) {
		clearTableViewer();
	}
	
	@Inject
	@Optional
	void onClientShutdown(final @UIEventTopic(Pi2Events.CLIENT_SHUTDOWN_FILELIST) String message) {
		clearTableViewer();
	}
	
	private void clearTableViewer() {
		viewer.setInput(new ArrayList<FileListItem>());
		viewer.refresh();
	}

}
